package com.android.launcher3;

import static android.util.Log.w;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;

import com.android.internal.util.XmlUtils;
import com.android.launcher3.LauncherSettings.Favorites;

public class LauncherProvider extends ContentProvider {

	private static final String LOG_TAG = "LauncherProvider";
	private static final boolean LOGD = true;
	private static final String DATABASE_NAME = "launcher.db";
	private static final int DATABASE_VERSION = 5;

	static final String AUTHORITY = "com.android.launcher3.settings";
	static final String EXTRA_BIND_SOURCES = "com.android.launcher3.settings.bindsources";
	static final String EXTRA_BIND_TARGETS = "com.android.launcher3.settings.bindtargets";
	static final String TABLE_FAVORITES = "favorites";
	static final String PARAMETER_NOTIFY = "notify";
	static final String TABLE_APPS = "apps";

	/**
	 * {@link Uri} triggered at any registered
	 * {@link android.database.ContentObserver} when
	 * {@link AppWidgetHost#deleteHost()} is called during database creation.
	 * Use this to recall {@link AppWidgetHost#startListening()} if needed.
	 */
	static final Uri CONTENT_APPWIDGET_RESET_URI = Uri.parse("content://"
			+ AUTHORITY + "/appWidgetReset");

	private SQLiteOpenHelper mOpenHelper;

	@Override
	public boolean onCreate() {
		mOpenHelper = new DatabaseHelper(getContext());

		return true;
	}

	@Override
	public String getType(Uri uri) {
		SqlArguments args = new SqlArguments(uri, null, null);

		if (TextUtils.isEmpty(args.where)) {
			return "vnd.android.cursor.dir/" + args.table;
		} else {
			return "vnd.android.cursor.item/" + args.table;
		}
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		qb.setTables(args.table);

		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		Cursor result = qb.query(db, projection, args.where, args.args, null,
				null, sortOrder);
		result.setNotificationUri(getContext().getContentResolver(), uri);

		return result;
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		SqlArguments args = new SqlArguments(uri);

		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		final long rowId = db.insert(args.table, null, initialValues);

		if (rowId <= 0) {
			return null;
		}

		uri = ContentUris.withAppendedId(uri, rowId);
		sendNotify(uri);

		return uri;
	}

	@Override
	public int bulkInsert(Uri uri, ContentValues[] values) {
		SqlArguments args = new SqlArguments(uri);

		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		db.beginTransaction();

		try {
			int numValues = values.length;

			for (int i = 0; i < numValues; i++) {
				if (db.insert(args.table, null, values[i]) < 0) {
					return 0;
				}
			}

			db.setTransactionSuccessful();
		} finally {
			db.endTransaction();
		}

		sendNotify(uri);

		return values.length;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SqlArguments args = new SqlArguments(uri, selection, selectionArgs);

		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count = db.delete(args.table, args.where, args.args);

		if (count > 0) {
			sendNotify(uri);
		}

		return count;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SqlArguments args = new SqlArguments(uri, selection, selectionArgs);

		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count = db.update(args.table, values, args.where, args.args);

		if (count > 0) {
			sendNotify(uri);
		}

		return count;
	}

	private void sendNotify(Uri uri) {
		String notify = uri.getQueryParameter(PARAMETER_NOTIFY);

		if ((notify == null) || "true".equals(notify)) {
			getContext().getContentResolver().notifyChange(uri, null);
		}
	}

	/**
	 * Build a query string that will match any row where the column matches
	 * anything in the values list.
	 */
	static String buildOrWhereString(String column, int[] values) {
		StringBuilder selectWhere = new StringBuilder();

		for (int i = values.length - 1; i >= 0; i--) {
			selectWhere.append(column).append("=").append(values[i]);

			if (i > 0) {
				selectWhere.append(" OR ");
			}
		}

		return selectWhere.toString();
	}

	private static class DatabaseHelper extends SQLiteOpenHelper {
		private static final String TAG_FAVORITES = "favorites";
		private static final String TAG_FAVORITE = "favorite";
		private static final String TAG_SHORTCUT = "shortcut";
		private static final String TAG_APPWIDGET = "appwidget";
		private static final String TAG_SEARCH = "search";
		private static final String TAG_TOPAPPS = "topapps";
		private final Context mContext;
		private final AppWidgetHost mAppWidgetHost;

		/**
		 * Creates a new DatabaseHelper object.
		 */
		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
			mContext = context;
			mAppWidgetHost = new AppWidgetHost(context,
					Launcher.APPWIDGET_HOST_ID);
		}

		/**
		 * Send notification that we've deleted the {@link AppWidgetHost},
		 * probably as part of the initial database creation. The receiver may
		 * want to re-call {@link AppWidgetHost#startListening()} to ensure
		 * callbacks are correctly set.
		 */
		private void sendAppWidgetResetNotify() {
			final ContentResolver resolver = mContext.getContentResolver();
			resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			if (LOGD) {
				Log.d(LOG_TAG, "creating new launcher database");
			}

			db.execSQL("CREATE TABLE favorites (" + "_id INTEGER PRIMARY KEY,"
					+ "title TEXT," + "intent TEXT," + "container INTEGER,"
					+ "screen INTEGER," + "cellX INTEGER," + "cellY INTEGER,"
					+ "spanX INTEGER," + "spanY INTEGER," + "itemType INTEGER,"
					+ "appWidgetId INTEGER NOT NULL DEFAULT -1,"
					+ "isShortcut INTEGER," + "iconType INTEGER,"
					+ "iconPackage TEXT," + "iconResource TEXT," + "icon BLOB,"
					+ "uri TEXT," + "displayMode INTEGER" + ");");

			db.execSQL("CREATE TABLE gestures (" + "_id INTEGER PRIMARY KEY,"
					+ "title TEXT," + "intent TEXT," + "itemType INTEGER,"
					+ "iconType INTEGER," + "iconPackage TEXT,"
					+ "iconResource TEXT," + "icon BLOB" + ");");

			db.execSQL("CREATE TABLE apps (_id INTEGER PRIMARY KEY,"
					+ "componentname TEXT,top_number "
					+ "INTEGER NOT NULL DEFAULT -1,"
					+ "page_number INTEGER NOT NULL DEFAULT -1,"
					+ "cell_number INTEGER NOT NULL DEFAULT -1);");

			// Database was just created, so wipe any previous widgets
			if (mAppWidgetHost != null) {
				mAppWidgetHost.deleteHost();
				sendAppWidgetResetNotify();
			}

			if (!convertDatabase(db)) {
				// Populate favorites table with initial favorites
				loadFavorites(db);
				loadTopApps(db);
				loadMainApps(db);
			}
		}

		private boolean addTopApp(SQLiteDatabase db,
				ContentValues paramContentValues, TypedArray paramTypedArray,
				PackageManager paramPackageManager, int paramInt) {
			String str1 = paramTypedArray.getString(1);
			String str2 = paramTypedArray.getString(0);

			try {
				ComponentName localComponentName = new ComponentName(str1, str2);
				paramPackageManager.getActivityInfo(localComponentName, 0);

				String str3 = localComponentName.flattenToString();
				paramContentValues.put(LauncherSettings.Apps.COMPONENT_NAME,
						str3);

				paramContentValues.put(LauncherSettings.Apps.TOP_NUMBER,
						paramInt);
				db.insert(TABLE_APPS, null, paramContentValues);

				return true;
			} catch (PackageManager.NameNotFoundException localNameNotFoundException) {
				localNameNotFoundException.printStackTrace();

				return false;
			}
		}

		private boolean convertDatabase(SQLiteDatabase db) {
			if (LOGD) {
				Log.d(LOG_TAG,
						"converting database from an older format, but not onUpgrade");
			}

			boolean converted = false;

			final Uri uri = Uri.parse("content://" + Settings.AUTHORITY
					+ "/old_favorites?notify=true");
			final ContentResolver resolver = mContext.getContentResolver();
			Cursor cursor = null;

			try {
				cursor = resolver.query(uri, null, null, null, null);
			} catch (Exception e) {
				// Ignore
			}

			// We already have a favorites database in the old provider
			if ((cursor != null) && (cursor.getCount() > 0)) {
				try {
					converted = copyFromCursor(db, cursor) > 0;
				} finally {
					cursor.close();
				}

				if (converted) {
					resolver.delete(uri, null, null);
				}
			}

			if (converted) {
				// Convert widgets from this import into widgets
				if (LOGD) {
					Log.d(LOG_TAG,
							"converted and now triggering widget upgrade");
				}

				convertWidgets(db);
			}

			return converted;
		}

		private int copyFromCursor(SQLiteDatabase db, Cursor c) {
			final int idIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
			final int intentIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
			final int titleIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
			final int iconTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
			final int iconIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
			final int iconPackageIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
			final int iconResourceIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
			final int containerIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
			final int itemTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
			final int screenIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
			final int cellXIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
			final int cellYIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
			final int uriIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
			final int displayModeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);

			ContentValues[] rows = new ContentValues[c.getCount()];
			int i = 0;

			while (c.moveToNext()) {
				ContentValues values = new ContentValues(c.getColumnCount());
				values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
				values.put(LauncherSettings.Favorites.INTENT,
						c.getString(intentIndex));
				values.put(LauncherSettings.Favorites.TITLE,
						c.getString(titleIndex));
				values.put(LauncherSettings.Favorites.ICON_TYPE,
						c.getInt(iconTypeIndex));
				values.put(LauncherSettings.Favorites.ICON,
						c.getBlob(iconIndex));
				values.put(LauncherSettings.Favorites.ICON_PACKAGE,
						c.getString(iconPackageIndex));
				values.put(LauncherSettings.Favorites.ICON_RESOURCE,
						c.getString(iconResourceIndex));
				values.put(LauncherSettings.Favorites.CONTAINER,
						c.getInt(containerIndex));
				values.put(LauncherSettings.Favorites.ITEM_TYPE,
						c.getInt(itemTypeIndex));
				values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
				values.put(LauncherSettings.Favorites.SCREEN,
						c.getInt(screenIndex));
				values.put(LauncherSettings.Favorites.CELLX,
						c.getInt(cellXIndex));
				values.put(LauncherSettings.Favorites.CELLY,
						c.getInt(cellYIndex));
				values.put(LauncherSettings.Favorites.URI,
						c.getString(uriIndex));
				values.put(LauncherSettings.Favorites.DISPLAY_MODE,
						c.getInt(displayModeIndex));
				rows[i++] = values;
			}

			db.beginTransaction();

			int total = 0;

			try {
				int numValues = rows.length;

				for (i = 0; i < numValues; i++) {
					if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
						return 0;
					} else {
						total++;
					}
				}

				db.setTransactionSuccessful();
			} finally {
				db.endTransaction();
			}

			return total;
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			if (LOGD) {
				Log.d(LOG_TAG, "onUpgrade triggered");
			}

			int version = oldVersion;

			if (version < 3) {
				// upgrade 1,2 -> 3 added appWidgetId column
				db.beginTransaction();

				try {
					// Insert new column for holding appWidgetIds
					db.execSQL("ALTER TABLE favorites "
							+ "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
					db.setTransactionSuccessful();
					version = 3;
				} catch (SQLException ex) {
					// Old version remains, which means we wipe old data
					Log.e(LOG_TAG, ex.getMessage(), ex);
				} finally {
					db.endTransaction();
				}

				// Convert existing widgets only if table upgrade was successful
				if (version == 3) {
					convertWidgets(db);
				}
			}

			if (version < 4) {
				version = 4;
			}

			if (version < 5) {
				if (updateContactsShortcuts(db)) {
					version = 5;
				}
			}

			if (version != DATABASE_VERSION) {
				Log.w(LOG_TAG, "Destroying all old data.");
				db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
				onCreate(db);
			}
		}

		private boolean updateContactsShortcuts(SQLiteDatabase db) {
			Cursor c = null;
			final String selectWhere = buildOrWhereString(
					LauncherSettings.Favorites.ITEM_TYPE,
					new int[] { LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT });

			db.beginTransaction();

			try {
				// Select and iterate through each matching widget
				c = db.query(TABLE_FAVORITES, new String[] {
						LauncherSettings.Favorites._ID,
						LauncherSettings.Favorites.INTENT }, selectWhere, null,
						null, null, null);

				if (LOGD) {
					Log.d(LOG_TAG, "found upgrade cursor count=" + c.getCount());
				}

				final ContentValues values = new ContentValues();
				final int idIndex = c
						.getColumnIndex(LauncherSettings.Favorites._ID);
				final int intentIndex = c
						.getColumnIndex(LauncherSettings.Favorites.INTENT);

				while ((c != null) && c.moveToNext()) {
					long favoriteId = c.getLong(idIndex);
					final String intentUri = c.getString(intentIndex);

					if (intentUri != null) {
						try {
							Intent intent = Intent.parseUri(intentUri, 0);
							android.util.Log.d("Home", intent.toString());

							final Uri uri = intent.getData();
							final String data = uri.toString();

							if (Intent.ACTION_VIEW.equals(intent.getAction())
									&& (data.startsWith("content://contacts/people/") || data
											.startsWith("content://com.android.contacts/contacts/lookup/"))) {
								intent = new Intent(
										"com.android.contacts.action.QUICK_CONTACT");
								intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
										| Intent.FLAG_ACTIVITY_CLEAR_TOP
										| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

								intent.setData(uri);
								intent.putExtra("mode", 3);
								intent.putExtra("exclude_mimes",
										(String[]) null);

								values.clear();
								values.put(LauncherSettings.Favorites.INTENT,
										intent.toUri(0));

								String updateWhere = LauncherSettings.Favorites._ID
										+ "=" + favoriteId;
								db.update(TABLE_FAVORITES, values, updateWhere,
										null);
							}
						} catch (RuntimeException ex) {
							Log.e(LOG_TAG, "Problem upgrading shortcut", ex);
						} catch (URISyntaxException e) {
							Log.e(LOG_TAG, "Problem upgrading shortcut", e);
						}
					}
				}

				db.setTransactionSuccessful();
			} catch (SQLException ex) {
				Log.w(LOG_TAG, "Problem while upgrading contacts", ex);

				return false;
			} finally {
				db.endTransaction();

				if (c != null) {
					c.close();
				}
			}

			return true;
		}

		/**
		 * Upgrade existing clock and photo frame widgets into their new widget
		 * equivalents. This method allocates appWidgetIds, and then hands off
		 * to LauncherAppWidgetBinder to finish the actual binding.
		 */
		private void convertWidgets(SQLiteDatabase db) {
			final int[] bindSources = new int[] {
					Favorites.ITEM_TYPE_WIDGET_CLOCK,
					Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME, };

			final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
			bindTargets.add(new ComponentName("com.android.alarmclock",
					"com.android.alarmclock.AnalogAppWidgetProvider"));
			bindTargets.add(new ComponentName("com.android.camera",
					"com.android.camera.PhotoAppWidgetProvider"));

			final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
					bindSources);

			Cursor c = null;
			boolean allocatedAppWidgets = false;

			db.beginTransaction();

			try {
				// Select and iterate through each matching widget
				c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID },
						selectWhere, null, null, null, null);

				if (LOGD) {
					Log.d(LOG_TAG, "found upgrade cursor count=" + c.getCount());
				}

				final ContentValues values = new ContentValues();

				while ((c != null) && c.moveToNext()) {
					long favoriteId = c.getLong(0);

					// Allocate and update database with new appWidgetId
					try {
						int appWidgetId = mAppWidgetHost.allocateAppWidgetId();

						if (LOGD) {
							Log.d(LOG_TAG, "allocated appWidgetId="
									+ appWidgetId + " for favoriteId="
									+ favoriteId);
						}

						values.clear();
						values.put(LauncherSettings.Favorites.APPWIDGET_ID,
								appWidgetId);

						// Original widgets might not have valid spans when
						// upgrading
						values.put(LauncherSettings.Favorites.SPANX, 2);
						values.put(LauncherSettings.Favorites.SPANY, 2);

						String updateWhere = Favorites._ID + "=" + favoriteId;
						db.update(TABLE_FAVORITES, values, updateWhere, null);

						allocatedAppWidgets = true;
					} catch (RuntimeException ex) {
						Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
					}
				}

				db.setTransactionSuccessful();
			} catch (SQLException ex) {
				Log.w(LOG_TAG,
						"Problem while allocating appWidgetIds for existing widgets",
						ex);
			} finally {
				db.endTransaction();

				if (c != null) {
					c.close();
				}
			}

			// If any appWidgetIds allocated, then launch over to binder
			if (allocatedAppWidgets) {
				launchAppWidgetBinder(bindSources, bindTargets);
			}
		}

		/**
		 * Launch the widget binder that walks through the Launcher database,
		 * binding any matching widgets to the corresponding targets. We can't
		 * bind ourselves because our parent process can't obtain the
		 * BIND_APPWIDGET permission.
		 * 
		 * @param bindSources
		 * @param bindTargets
		 */
		private void launchAppWidgetBinder(int[] bindSources,
				ArrayList<ComponentName> bindTargets) {
			final Intent intent = new Intent();
			intent.setComponent(new ComponentName("com.android.settings",
					"com.android.settings.LauncherAppWidgetBinder"));
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

			final Bundle extras = new Bundle();
			extras.putIntArray(EXTRA_BIND_SOURCES, bindSources);
			extras.putParcelableArrayList(EXTRA_BIND_TARGETS, bindTargets);
			intent.putExtras(extras);

			mContext.startActivity(intent);
		}

		/**
		 * Loads the default set of favorite packages from an xml file.
		 * 
		 * @param db
		 *            The database to write the values into
		 * 
		 * @return
		 */
		private int loadFavorites(SQLiteDatabase db) {
			Intent intent = new Intent(Intent.ACTION_MAIN, null);
			intent.addCategory(Intent.CATEGORY_LAUNCHER);

			ContentValues values = new ContentValues();

			PackageManager packageManager = mContext.getPackageManager();
			int i = 0;

			try {
				XmlResourceParser parser = mContext.getResources().getXml(
						R.xml.default_workspace);
				AttributeSet attrs = Xml.asAttributeSet(parser);
				XmlUtils.beginDocument(parser, TAG_FAVORITES);

				final int depth = parser.getDepth();

				int type;

				while ((((type = parser.next()) != XmlPullParser.END_TAG) || (parser
						.getDepth() > depth))
						&& (type != XmlPullParser.END_DOCUMENT)) {
					if (type != XmlPullParser.START_TAG) {
						continue;
					}

					boolean added = false;
					final String name = parser.getName();

					TypedArray a = mContext.obtainStyledAttributes(attrs,
							R.styleable.Favorite);

					values.clear();
					values.put(LauncherSettings.Favorites.CONTAINER,
							LauncherSettings.Favorites.CONTAINER_DESKTOP);
					values.put(LauncherSettings.Favorites.SCREEN,
							a.getString(R.styleable.Favorite_screen));
					values.put(LauncherSettings.Favorites.CELLX,
							a.getString(R.styleable.Favorite_x));
					values.put(LauncherSettings.Favorites.CELLY,
							a.getString(R.styleable.Favorite_y));

					if (TAG_FAVORITE.equals(name)) {
						added = addAppShortcut(db, values, a, packageManager,
								intent);
					} else if (TAG_SEARCH.equals(name)) {
						added = addSearchWidget(db, values);
					} else if (TAG_APPWIDGET.equals(name)) {
						added = addAppWidget(db, values, a);
					} else if (TAG_SHORTCUT.equals(name)) {
						added = addShortcut(db, values, a);
					}

					if (added) {
						i++;
					}

					a.recycle();
				}
			} catch (XmlPullParserException e) {
				Log.w(LOG_TAG, "Got exception parsing favorites.", e);
			} catch (IOException e) {
				Log.w(LOG_TAG, "Got exception parsing favorites.", e);
			}

			return i;
		}

		private int loadTopApps(SQLiteDatabase paramSQLiteDatabase) {
			ContentValues values = new ContentValues();
			PackageManager packageManager = mContext.getPackageManager();
			int i = 0;

			try {
				XmlResourceParser parser = mContext.getResources().getXml(
						R.xml.default_topapplication);
				AttributeSet attrs = Xml.asAttributeSet(parser);
				XmlUtils.beginDocument(parser, TAG_TOPAPPS);

				final int depth = parser.getDepth();

				int type;

				while ((((type = parser.next()) != XmlPullParser.END_TAG) || (parser
						.getDepth() > depth))
						&& (type != XmlPullParser.END_DOCUMENT)) {
					if (type != XmlPullParser.START_TAG) {
						continue;
					}

					boolean added = false;
					TypedArray a = mContext.obtainStyledAttributes(attrs,
							R.styleable.TopApp);
					// String cls = a.getString(R.styleable.TopApp_className);
					// String pkg = a.getString(R.styleable.TopApp_packageName);
					// Log.e(""+cls,""+pkg);
					values.clear();
					added = addTopApp(paramSQLiteDatabase, values, a,
							packageManager, i);

					if (added) {
						i++;
					}

					a.recycle();
				}
			} catch (XmlPullParserException e) {
				Log.w(LOG_TAG, "Got exception parsing favorites.", e);
			} catch (IOException e) {
				Log.w(LOG_TAG, "Got exception parsing favorites.", e);
			}

			return i;
		}

		private int loadMainApps(SQLiteDatabase database) {
			ContentValues localContentValues = new ContentValues();
			PackageManager localPackageManager = mContext.getPackageManager();
			int i = 0;

			try {
				XmlResourceParser parser = mContext.getResources().getXml(
						R.xml.default_mainapplication_order);
				AttributeSet localAttributeSet = Xml.asAttributeSet(parser);
				XmlUtils.beginDocument(parser, "mainapps");

				int depth = parser.getDepth();
				int type;

				while ((((type = parser.next()) != XmlPullParser.END_TAG) || (parser
						.getDepth() > depth))
						&& (type != XmlPullParser.END_DOCUMENT)) {
					if (type != XmlPullParser.START_TAG) {
						continue;
					}

					String str = parser.getName();

					// /Log.d(LOG_TAG, "localXmlResourceParser:"+str);
					Context localContext = mContext;
					int[] arrayOfInt = R.styleable.MainApp;
					TypedArray localTypedArray = localContext
							.obtainStyledAttributes(localAttributeSet,
									arrayOfInt);
					localContentValues.clear();

					boolean bool = false;

					if ("mainapp".equals(str)) {
						bool = this.addMainApp(database, localContentValues,
								localTypedArray, localPackageManager, i);
					}

					if (bool) {
						i++;
					}

					localTypedArray.recycle();
				}

				return i;
			} catch (XmlPullParserException e) {
				e.printStackTrace();

				return i;
			} catch (IOException e2) {
				e2.printStackTrace();

				return i;
			}
		}

		private boolean addMainApp(SQLiteDatabase database,
				ContentValues paramContentValues, TypedArray paramTypedArray,
				PackageManager pm, int index) {
			String pkgName = paramTypedArray
					.getString(R.styleable.MainApp_packageName);
			String className = paramTypedArray
					.getString(R.styleable.MainApp_className);

			// int i = LauncherConfig.getItemNoOfPage(mContext);
			int i = mContext.getResources().getInteger(
					R.integer.item_num_of_page);

			try {
				ComponentName localComponentName = new ComponentName(pkgName,
						className);
				pm.getActivityInfo(localComponentName, 0);
				paramContentValues.put(LauncherSettings.Apps.COMPONENT_NAME,
						localComponentName.flattenToString());
				paramContentValues.put(LauncherSettings.Apps.PAGE_NUMBER, index
						/ i);
				paramContentValues.put(LauncherSettings.Apps.CELL_NUMBER, index
						% i);
				database.insert(TABLE_APPS, null, paramContentValues);

				return true;
			} catch (PackageManager.NameNotFoundException e) {
				e.printStackTrace();

				return false;
			}
		}

		private boolean addAppShortcut(SQLiteDatabase db, ContentValues values,
				TypedArray a, PackageManager packageManager, Intent intent) {
			ActivityInfo info;
			String packageName = a.getString(R.styleable.Favorite_packageName);
			String className = a.getString(R.styleable.Favorite_className);

			try {
				ComponentName cn = new ComponentName(packageName, className);
				info = packageManager.getActivityInfo(cn, 0);
				intent.setComponent(cn);
				intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
						| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
				values.put(Favorites.INTENT, intent.toUri(0));
				values.put(Favorites.TITLE, info.loadLabel(packageManager)
						.toString());
				values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
				values.put(Favorites.SPANX, 1);
				values.put(Favorites.SPANY, 1);
				db.insert(TABLE_FAVORITES, null, values);
			} catch (PackageManager.NameNotFoundException e) {
				Log.w(LOG_TAG, "Unable to add favorite: " + packageName + "/"
						+ className, e);

				return false;
			}

			return true;
		}

		private boolean addShortcut(SQLiteDatabase db, ContentValues values,
				TypedArray a) {
			Resources r = mContext.getResources();

			final int iconResId = a.getResourceId(R.styleable.Favorite_icon, 0);
			final int titleResId = a.getResourceId(R.styleable.Favorite_title,
					0);

			Intent intent;
			String uri = null;

			try {
				uri = a.getString(R.styleable.Favorite_uri);
				intent = Intent.parseUri(uri, 0);
			} catch (URISyntaxException e) {
				w(LauncherModel.LOG_TAG, "Shortcut has malformed uri: " + uri);

				return false; // Oh well
			}

			if ((iconResId == 0) || (titleResId == 0)) {
				w(LauncherModel.LOG_TAG,
						"Shortcut is missing title or icon resource ID");

				return false;
			}

			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			values.put(Favorites.INTENT, intent.toUri(0));
			values.put(Favorites.TITLE, r.getString(titleResId));
			values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT);
			values.put(Favorites.SPANX, 1);
			values.put(Favorites.SPANY, 1);
			values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
			values.put(Favorites.ICON_PACKAGE, mContext.getPackageName());
			values.put(Favorites.ICON_RESOURCE, mContext.getResources()
					.getResourceName(iconResId));

			db.insert(TABLE_FAVORITES, null, values);

			return true;
		}

		private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
			// Add a search box
			values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_SEARCH);
			values.put(Favorites.SPANX, 4);
			values.put(Favorites.SPANY, 1);
			db.insert(TABLE_FAVORITES, null, values);

			return true;
		}

		private boolean addAppWidget(SQLiteDatabase db, ContentValues values,
				TypedArray a) {
			String packageName = a.getString(R.styleable.Favorite_packageName);
			String className = a.getString(R.styleable.Favorite_className);
			if (packageName == null || className == null) {
				return false;
			}

			ComponentName cn = new ComponentName(packageName, className);

			boolean allocatedAppWidgets = false;
			final AppWidgetManager appWidgetManager = AppWidgetManager
					.getInstance(mContext);

			try {
				int appWidgetId = mAppWidgetHost.allocateAppWidgetId();

				values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
				values.put(Favorites.SPANX,
						a.getString(R.styleable.Favorite_spanX));
				values.put(Favorites.SPANY,
						a.getString(R.styleable.Favorite_spanY));
				values.put(Favorites.APPWIDGET_ID, appWidgetId);
				db.insert(TABLE_FAVORITES, null, values);
				allocatedAppWidgets = true;

				appWidgetManager.bindAppWidgetId(appWidgetId, cn);
			} catch (RuntimeException ex) {
				Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
			}

			return allocatedAppWidgets;
		}

	}

	static class SqlArguments {
		public final String table;
		public final String where;
		public final String[] args;

		/**
		 * Creates a new SqlArguments object.
		 */
		SqlArguments(Uri url, String where, String[] args) {
			if (url.getPathSegments().size() == 1) {
				this.table = url.getPathSegments().get(0);
				this.where = where;
				this.args = args;
			} else if (url.getPathSegments().size() != 2) {
				throw new IllegalArgumentException("Invalid URI: " + url);
			} else if (!TextUtils.isEmpty(where)) {
				throw new UnsupportedOperationException(
						"WHERE clause not supported: " + url);
			} else {
				this.table = url.getPathSegments().get(0);
				this.where = "_id=" + ContentUris.parseId(url);
				this.args = null;
			}
		}

		/**
		 * Creates a new SqlArguments object.
		 */
		SqlArguments(Uri url) {
			if (url.getPathSegments().size() == 1) {
				table = url.getPathSegments().get(0);
				where = null;
				args = null;
			} else {
				throw new IllegalArgumentException("Invalid URI: " + url);
			}
		}
	}
}
